package cn.stylefeng.guns.modular.business.service.impl;

import cn.stylefeng.guns.api.core.exception.RestExceptionEnum;
import cn.stylefeng.guns.base.consts.ConstantsContext;
import cn.stylefeng.guns.config.redis.redis.util.Redishandler0;
import cn.stylefeng.guns.core.RecoverConst;
import cn.stylefeng.guns.core.UserGradeLevel;
import cn.stylefeng.guns.modular.business.entity.Certification;
import cn.stylefeng.guns.modular.business.entity.UserGrade;
import cn.stylefeng.guns.modular.business.entity.UserProperty;
import cn.stylefeng.guns.modular.business.model.result.UserInformationResult;
import cn.stylefeng.guns.modular.business.service.AccountService;
import cn.stylefeng.guns.modular.business.service.CertificationService;
import cn.stylefeng.guns.modular.business.service.UserGradeService;
import cn.stylefeng.guns.modular.business.service.UserPropertyService;
import cn.stylefeng.guns.sms.core.enums.SmsSendSource;
import cn.stylefeng.guns.sms.core.enums.SmsSendStatus;
import cn.stylefeng.guns.sms.core.sms.SmsManager;
import cn.stylefeng.guns.sms.modular.entity.SmsInfo;
import cn.stylefeng.guns.sms.modular.model.SendMessageParam;
import cn.stylefeng.guns.sys.core.constant.Const;
import cn.stylefeng.guns.sys.core.exception.enums.BizExceptionEnum;
import cn.stylefeng.guns.sys.core.shiro.ShiroKit;
import cn.stylefeng.guns.sys.core.util.IdGen;
import cn.stylefeng.guns.sys.core.util.IdGenerator;
import cn.stylefeng.guns.sys.core.util.StringUtils;
import cn.stylefeng.guns.sys.modular.system.entity.Dict;
import cn.stylefeng.guns.sys.modular.system.entity.DictType;
import cn.stylefeng.guns.sys.modular.system.entity.Role;
import cn.stylefeng.guns.sys.modular.system.entity.User;
import cn.stylefeng.guns.sys.modular.system.factory.UserFactory;
import cn.stylefeng.guns.sys.modular.system.mapper.UserMapper;
import cn.stylefeng.guns.sys.modular.system.model.UserDto;
import cn.stylefeng.guns.sys.modular.system.service.DictService;
import cn.stylefeng.guns.sys.modular.system.service.DictTypeService;
import cn.stylefeng.guns.sys.modular.system.service.UserService;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import weixin.popular.api.TokenAPI;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 用户属性表 服务实现类
 * </p>
 *
 * @author jwj
 * @since 2019-07-19
 */
@Service
@Slf4j
public class AccountServiceImpl extends ServiceImpl<UserMapper, User> implements AccountService {

    @Autowired
    private UserService userService;

    @Autowired
    private Redishandler0 redishandler0;

    @Autowired
    private UserPropertyService userPropertyService;

    @Autowired
    private UserGradeService userGradeService;

    @Autowired
    private DictService dictService;

    @Autowired
    private DictTypeService dictTypeService;

    @Autowired
    private SmsManager smsManager;

    @Autowired
    private CertificationService certificationService;

    /**
     * 微信appid
     */
    @Value("${wx.appid}")
    private String appId;

    /**
     * 微信秘钥
     */
    @Value("${wx.appsecret}")
    private String appSecret;

    /**
     * 注册
     *
     * @param param
     * @author jwj
     * @Date 2019-07-18
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reg(UserDto param) {
        // 判断账号是否重复
        User theUser = userService.getByAccount(param.getAccount());
        if (theUser != null) {
            throw new ServiceException(BizExceptionEnum.USER_ALREADY_REG);
        }

        // 完善账号信息
        String salt = ShiroKit.getRandomSalt(5);
        String password = ShiroKit.md5(param.getPassword(), salt);
        User newUser = UserFactory.createUser(param, password, salt);
        String gunsWebAccountDeptId = (String) ConstantsContext.getConstntsMap().get("GUNS_WEB_ACCOUNT_DEPT");
        newUser.setDeptId(Long.valueOf(gunsWebAccountDeptId));
        //分配前端用户角色
        String gunsWebAccountRoleKey = (String) ConstantsContext.getConstntsMap().get("GUNS_WEB_ROLE");
        String roleStr = redishandler0.getHash(Const.SYS_ROLE_KEY, "", gunsWebAccountRoleKey);
        if (StringUtils.isNotEmpty(roleStr)) {
            Role role = JSONObject.parseObject(roleStr, Role.class);
            newUser.setRoleId(role.getRoleId().toString());
        }
        newUser.setRefeeInfo(IdGen.randomString(6));
        newUser.setAmount(new BigDecimal(0));
        newUser.setMessagePush("0");
        userService.save(newUser);
        //处理推荐关系
        if (StringUtils.isNotEmpty(param.getRefeeInfo())) {
            boolean result = saveRecommendRelation(newUser, param.getRefeeInfo());
            if (result) {
                throw new ServiceException(RestExceptionEnum.REFEE_SAVE_ERROR);
            }
        }
    }

    /**
     * 保存推荐关系
     *
     * @param accountInfo 账号信息
     * @param refereeInfo 推荐码
     * @return boolean
     */
    private boolean saveRecommendRelation(User accountInfo, String refereeInfo) {
        UserProperty recommendUser = new UserProperty();
        recommendUser.setUserId(accountInfo.getUserId());
        UserGrade grade = getGrade(UserGradeLevel.first_level.getCode());
        recommendUser.setGradeId(grade.getGradeId());
        recommendUser.setGradeLevel(grade.getLevel());
        if (StringUtils.isNotBlank(refereeInfo)) {
            User parentAccount = userService.getOne(new QueryWrapper<User>().eq("referee_info", refereeInfo).eq("delete_flag", RecoverConst.DEL_FLAG_FALSE));
            if (parentAccount != null) {
                UserProperty recommendUser1 = userPropertyService.getOne(new QueryWrapper<UserProperty>().eq("user_id", parentAccount.getUserId()).eq("delete_flag", RecoverConst.DEL_FLAG_FALSE));
                recommendUser.setParentId(parentAccount.getUserId());
                recommendUser.setParentGradeId(recommendUser1.getGradeId());
                recommendUser.setRelationPath(recommendUser1.getRelationPath() + "-" + parentAccount.getUserId());
            }
        }
        recommendUser.setUserId(accountInfo.getUserId());
        return userPropertyService.save(recommendUser);
    }

    private UserGrade getGrade(int level) {
        String gradeStr = redishandler0.getHash(RecoverConst.USER_GRADE_REDIS_KEY, "", level + "");
        UserGrade grade = JSONObject.parseObject(gradeStr, UserGrade.class);
        return grade;
    }

    /**
     * 个人信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserInformationResult information(long userId) {
        User user = getUser(userId);
        UserInformationResult userInformationResult = new UserInformationResult();
        ToolUtil.copyProperties(user, userInformationResult);
        //获取用户等级
        UserProperty userProperty = Optional.ofNullable(userPropertyService.getOne(new QueryWrapper<UserProperty>().eq("user_id", userId).eq("delete_flag", RecoverConst.DEL_FLAG_FALSE))).orElse(new UserProperty());
        UserGrade userGrade = getGrade(userProperty.getGradeLevel() == null ? 1 : userProperty.getGradeLevel());
        userInformationResult.setGradeName(Optional.ofNullable(userGrade).orElse(new UserGrade()).getGradeName());
        //实名认证
        Certification certification = certificationService.findByUserId(userId);
        if (null == certification) {
            userInformationResult.setCertification("3");
        } else {
            userInformationResult.setCertification(certification.getStatus());
        }
        return userInformationResult;
    }

    private User getUser(long userId) {
        return Optional.ofNullable(userService.getById(userId)).orElseThrow(()-> new ServiceException(BizExceptionEnum.NO_THIS_USER));
    }

    /**
     * 修改用户昵称
     *
     * @param userId 用户id
     * @param name   昵称
     */
    @Override
    public boolean updateName(long userId, String name) {
        User user = getUser(userId);
        user.setName(name);
        user.setUpdateTime(new Date());
        return userService.updateById(user);
    }

    /**
     * 接收微信消息推送
     *
     * @param userId      用户id
     * @param messagePush 接收消息推送（0：接收，1：拒绝）
     * @return
     */
    @Override
    public boolean messagePush(long userId, String messagePush) {
        User user = getUser(userId);
        user.setMessagePush(messagePush);
        user.setUpdateTime(new Date());
        return userService.updateById(user);
    }

    /**
     * 修改手机号
     *
     * @param userId   用户id
     * @param oldPhone 旧手机号
     * @param newPhone 新手机号
     * @param smsCode  验证码
     * @return
     */
    @Override
    public boolean changePhone(long userId, String oldPhone, String newPhone, String smsCode) {
        User user = getUser(userId);
        if (!user.getPhone().equals(oldPhone)) {
            throw new ServiceException(500, "原手机号不存在");
        }
        //TODO 验证码校验
        user.setPhone(newPhone);
        user.setUpdateTime(new Date());

        return userService.updateById(user);
    }

    /**
     * 修改密码
     *
     * @param userId      用户id
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @return
     */
    @Override
    public boolean changePassword(long userId, String oldPassword, String newPassword) {
        User user = getUser(userId);
        if (!user.getPassword().equals(ShiroKit.md5(oldPassword, user.getSalt()))) {
            throw new ServiceException(BizExceptionEnum.OLD_PWD_NOT_RIGHT);
        }
        String password = ShiroKit.md5(newPassword, user.getSalt());
        user.setPassword(password);
        user.setUpdateTime(new Date());
        return userService.updateById(user);
    }

    /**
     * 联系我们
     *
     * @return
     */
    @Override
    public List<Dict> contactUs() {
        DictType dictType = Optional.ofNullable(dictTypeService.getOne(new QueryWrapper<DictType>().eq("code", "CONTACT_US"))).orElseThrow(() -> new ServiceException(400, "请先在字典中配置联系我们"));
        return dictService.list(new QueryWrapper<Dict>().eq("dict_type_id", dictType.getDictTypeId()));
    }

    /**
     * 发送短信
     *
     * @param phone
     * @param TemplateCode
     * @return
     */
    @Override
    public boolean sendSMS(String phone, String TemplateCode) {
        SendMessageParam param = new SendMessageParam();
        Map<String, Object> params = new HashMap<>();
        //六位随机码
        String code = IdGenerator.createXCode(6);
        params.put("code", code);
        smsManager.sendSms(param.getPhoneNumbers(), TemplateCode, params);
        SmsInfo smsInfo = new SmsInfo();
        smsInfo.setCreateTime(new Date());
        smsInfo.setPhoneNumbers(phone);
        smsInfo.setStatus(SmsSendStatus.WAITING.getCode());
        smsInfo.setSource(SmsSendSource.WEB.getCode());
        smsInfo.setTemplateCode(TemplateCode);
        //TODO 保存数据库以后查明细
        redishandler0.cacheStringValue(RecoverConst.REDISPREFIX_CODE, phone, code, RecoverConst.CODE_EXPIRE_TIME);
        return true;
    }

    /**
     * 验证短信
     *
     * @param phone
     * @param code
     * @return
     */
    @Override
    public boolean invalidSMS(String phone, String code) {
        //根据缓存获取验证码
        String sendCode = redishandler0.getStringValue(RecoverConst.REDISPREFIX_CODE, phone);
        if (StringUtils.isEmpty(sendCode)) {
            return false;
        }
        if (!sendCode.equals(code)) {
            return false;
        } else {
            //验证成功后，删除验证码
            redishandler0.remove(RecoverConst.REDISPREFIX_CODE, phone);
            return true;

        }
    }

    @Override
    public String getWxToken() {
        try {
            return TokenAPI.token(appId, appSecret).getAccess_token();
        } catch (Exception e) {
            throw new ServiceException(BizExceptionEnum.GET_ACCESS_TOKEN_FAIL);
        }
    }
}
